﻿/**
 * ...
 * @author Sergey Mamyan
 */

package tx.squirrel.neko.core.model;

import haxe.Md5;
import haxe.Stack;
import tx.json.JSON;
import neko.db.Object;
import neko.db.Manager;
import neko.Lib;
import neko.Web;
import tx.squirrel.neko.core.Engine;

class Session extends Object {
	
	static var UID_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	
	public static var manager = new SessionManager();
	public static var data:Hash<Dynamic> = new Hash<String>();
	
	static public var session:Session;
	
	public static function writeLog(type:String, title:String, ?obj:Dynamic):Void {
		var errors:Array < Dynamic >;
		if (data.exists("LOG")) {
			errors = data.get("LOG");
		}else {
			errors = new Array<Dynamic>();
		}
		errors.push( {type:type, title:title, data:obj } );
		data.set("LOG",errors);
	}
	
	public static function readLog():Array < Dynamic > {
		var errors:Array < Dynamic >;
		if (data.exists("LOG")) {
			var log:Array < Dynamic > = data.get("LOG");
			data.remove("LOG");
			return log;
		}else {
			return null;
		}
	}
	
	static function makeSessionId() : String {
		var nchars = UID_CHARS.length;
		var k = "";
		for (i in 0 ... 32){
			k += UID_CHARS.charAt( Std.int(Math.random() * nchars) );
		}
		return k;
	}
	
	static public function open() : Void {
		if (session != null) { return; }
		
		var fbSessionId:String 		= Engine.request.getSessionId();
		var fbAppId:String 			= Engine.request.getAppId();
		var fbUserId:String 		= Engine.request.getUserId();
		var fbType:String 			= Engine.request.getType();
		
		if (fbSessionId == null || fbSessionId.length == 0) {
			fbSessionId = makeSessionId();
		}
		
		session	= manager.getById(fbSessionId);
		if (session == null) {
			session 		= new Session();
			session.id 		= fbSessionId;
			session.appId	= fbAppId;
			session.userId 	= fbUserId;
			session.type	= fbType;
			session.insert();
		}
		
		Web.setHeader("Set-Cookie", "SID=" + session.id + "; path=/");
	}
	
	
	
	static private function openWebSession() : Void {
		var webSid:String = Web.getCookies().get("SID");
		if (Web.getParams().exists("SID")) {
			webSid = Web.getParams().get("SID");
		}
		
		session = Session.manager.getById(webSid);
		
		
		
		if(session.sData != null){
			data = Lib.unserialize(session.sData);
		}else {
			data = new Hash<Dynamic>();
		}
		
		
	}
	
	static public function close() : Void {
		if (session == null) { return; }
		if(data != null){
			session.sData = Lib.serialize(data);
		}
		session.update();
		session = null;
		data = null;
		var rand:Int = Std.random(2);
		if (rand == 1){
			Session.manager.cleanUp();
		}
	}
	
	public static function getApp():Application {
		return Application.manager.getById(session.appId);
	}
	
	public static function getUser():User {
		return User.manager.getById(session.userId);
	}
	
	public var id:String;
	public var type:String; // FACEBOOK, WEB, ...
	public var userId:String;
	public var appId:String;
	public var sInfo:String;
	public var sData:String;
	public var createTime:Date;
	public var modifyTime:Date;
	
	public function new(){
		super();
		sData 		= Lib.serialize(new Hash<Dynamic>());
		sInfo		= JSON.encode({
			headers	:Web.getClientHeaders(),
			method	:Web.getMethod(),
			params	:Web.getParams(),
			ip		:Web.getClientIP(),
			uri		:Web.getURI()
		});
		createTime 	= Date.now();
		modifyTime 	= Date.now();
	}
	
	override public function update(){
		modifyTime = Date.now();
		super.update();
	}
	
	override public function toString() {
		return "Session { \n\t id : " + id + ",\n\t appId : " + appId + ",\n\t userId : " + userId + "\n}";
	}
}

class SessionManager extends Manager<Session> {

	public function new(){
		super(Session);
	}

	public function getById( sId:String ) : Session {
		return object(select("id='"+sId+"'"), true);
	}
	
	public function cleanUp() {
		var limit = Date.fromTime(Date.now().getTime() - 60*60*1000);
		execute("DELETE FROM Session WHERE modifyTime < "+quote(limit.toString()));
	}
}